`timescale 1ns/100ps

module cm_fft2_N8 #(
    parameter C_DATA_WITH = 16
)(
    input  wire                     I_sys_clk,       // 工作时钟 100M
    input  wire                     I_data_start,    // 数据开始进入标志，与第一个数据对齐输入
    input  wire [C_DATA_WITH-1:0]   I_data_in_real,  // 数据输入，从start开始连续输入
    input  wire [C_DATA_WITH-1:0]   I_data_in_imag,  // 数据输入，从start开始连续输入
    output wire                     O_data_start,    // 数据开始输出标志与第一个数据对齐输出
    output wire [C_DATA_WITH+2:0]   O_data_out_real, // 数据输出，从start开始连续输出
    output wire [C_DATA_WITH+2:0]   O_data_out_imag  // 数据输出，从start开始连续输出
);

// ============================================================
// 内部参数
// ============================================================
/// W08=1
/// W18=0.707 - 0.707*1j
/// W28=-1j
/// W38=-0.707 - 0.707*1j

// ============================================================
// 变量声明
// ============================================================
reg                      S_data_start_d1;
reg                      S_data_start_d2;
reg                      S_data_start_d3;
reg                      S_data_start_d4;
reg                      S_data_start_d5;
reg                      S_data_start_d6;
reg                      S_data_start_d7;
reg                      S_data_start_d8;
reg                      S_data_start_d9;
reg                      S_data_start_d10;
reg                      S_data_start_d11;
reg                      S_data_start_d12;

reg  [C_DATA_WITH-1:0]   S_data_in_real_d1;
reg  [C_DATA_WITH-1:0]   S_data_in_real_d2;
reg  [C_DATA_WITH-1:0]   S_data_in_real_d3;
reg  [C_DATA_WITH-1:0]   S_data_in_real_d4;
reg  [C_DATA_WITH-1:0]   S_data_in_real_d5;
reg  [C_DATA_WITH-1:0]   S_data_in_real_d6;

reg  [C_DATA_WITH-1:0]   S_data_in_imag_d1;
reg  [C_DATA_WITH-1:0]   S_data_in_imag_d2;
reg  [C_DATA_WITH-1:0]   S_data_in_imag_d3;
reg  [C_DATA_WITH-1:0]   S_data_in_imag_d4;
reg  [C_DATA_WITH-1:0]   S_data_in_imag_d5;
reg  [C_DATA_WITH-1:0]   S_data_in_imag_d6;

reg  [11:0]              S_Wn8_real;
reg  [11:0]              S_Wn8_imag;

reg  [C_DATA_WITH:0]     S_data_cut_real;
reg  [C_DATA_WITH:0]     S_data_cut_imag;

wire [C_DATA_WITH+13:0]  S_data_multW_real; // X2
wire [C_DATA_WITH+13:0]  S_data_multW_imag; // X2

reg  [C_DATA_WITH:0]     S_data_add_real;   // x1
reg  [C_DATA_WITH:0]     S_data_add_imag;   // x1

wire [C_DATA_WITH:0]     S_data_out_real;   // x1 X2
wire [C_DATA_WITH:0]     S_data_out_imag;   // x1 X2

// ============================================================
// 主逻辑代码
// ============================================================

// 同步输入的 start 标志
always @(posedge I_sys_clk) begin
    S_data_start_d1   <= I_data_start;
    S_data_start_d2   <= S_data_start_d1;
    S_data_start_d3   <= S_data_start_d2;
    S_data_start_d4   <= S_data_start_d3;
    S_data_start_d5   <= S_data_start_d4;
    S_data_start_d6   <= S_data_start_d5;
    S_data_start_d7   <= S_data_start_d6;
    S_data_start_d8   <= S_data_start_d7;
    S_data_start_d9   <= S_data_start_d8;
    S_data_start_d10  <= S_data_start_d9;
    S_data_start_d11  <= S_data_start_d10;
    S_data_start_d12  <= S_data_start_d11;
end

// 缓存输入数据
always @(posedge I_sys_clk) begin
    S_data_in_real_d1 <= I_data_in_real;
    S_data_in_real_d2 <= S_data_in_real_d1;
    S_data_in_real_d3 <= S_data_in_real_d2;
    S_data_in_real_d4 <= S_data_in_real_d3;
    S_data_in_real_d5 <= S_data_in_real_d4;
    S_data_in_real_d6 <= S_data_in_real_d5;

    S_data_in_imag_d1 <= I_data_in_imag;
    S_data_in_imag_d2 <= S_data_in_imag_d1;
    S_data_in_imag_d3 <= S_data_in_imag_d2;
    S_data_in_imag_d4 <= S_data_in_imag_d3;
    S_data_in_imag_d5 <= S_data_in_imag_d4;
    S_data_in_imag_d6 <= S_data_in_imag_d5;
end

// 计算数据差值
always @(posedge I_sys_clk) begin
    S_data_cut_real <= {S_data_in_real_d4[C_DATA_WITH-1], S_data_in_real_d4} - 
                       {I_data_in_real[C_DATA_WITH-1], I_data_in_real};
    S_data_cut_imag <= {S_data_in_imag_d4[C_DATA_WITH-1], S_data_in_imag_d4} - 
                       {I_data_in_imag[C_DATA_WITH-1], I_data_in_imag};
end

// 生成旋转因子 (Twiddle Factor)
always @(*) begin
    if (S_data_start_d5) begin
        S_Wn8_real = 12'd1024;
        S_Wn8_imag = 12'd0;
    end else if (S_data_start_d6) begin
        S_Wn8_real = 12'd724;
        S_Wn8_imag = -12'd724;
    end else if (S_data_start_d7) begin
        S_Wn8_real = 12'd0;
        S_Wn8_imag = -12'd1024;
    end else begin
        S_Wn8_real = -12'd724;
        S_Wn8_imag = -12'd724;
    end
end

// 调用复乘模块 (Complex Multiplier)
cmult # (
    .AWIDTH(C_DATA_WITH+1),
    .BWIDTH(12)
) u0_cmult (
    .clk(I_sys_clk),
    .ar(S_data_cut_real),
    .ai(S_data_cut_imag),
    .br(S_Wn8_real),
    .bi(S_Wn8_imag),
    .pr(S_data_multW_real),
    .pi(S_data_multW_imag)
);

// 计算数据和
always @(posedge I_sys_clk) begin
    S_data_add_real <= {S_data_in_real_d6[C_DATA_WITH-1], S_data_in_real_d6} + 
                       {S_data_in_real_d2[C_DATA_WITH-1], S_data_in_real_d2};
    S_data_add_imag <= {S_data_in_imag_d6[C_DATA_WITH-1], S_data_in_imag_d6} + 
                       {S_data_in_imag_d2[C_DATA_WITH-1], S_data_in_imag_d2};
end

// 输出选择逻辑
assign S_data_out_real = (S_data_start_d7 | S_data_start_d8 | S_data_start_d9 | S_data_start_d10) ? 
                         S_data_add_real : 
                         (S_data_multW_real[10+:C_DATA_WITH+1] + S_data_multW_real[9]);

assign S_data_out_imag = (S_data_start_d7 | S_data_start_d8 | S_data_start_d9 | S_data_start_d10) ? 
                         S_data_add_imag : 
                         (S_data_multW_imag[10+:C_DATA_WITH+1] + S_data_multW_imag[9]);

// 实例化子模块：cm_fft2_N4
cm_fft2_N4 #(
    .C_DATA_WITH(C_DATA_WITH+1)
) u0_cm_fft2_N4 (
    .I_sys_clk(I_sys_clk),                               // 工作时钟 100M
    .I_data_start(S_data_start_d7 | S_data_start_d11),  // 数据开始进入标志
    .I_data_in_real(S_data_out_real),                   // 数据输入
    .I_data_in_imag(S_data_out_imag),                   // 数据输入
    .O_data_start(),                                    // 数据开始输出标志
    .O_data_out_real(O_data_out_real),                  // 数据输出
    .O_data_out_imag(O_data_out_imag)                   // 数据输出
);

// 输出 start 标志
assign O_data_start = S_data_start_d12;

endmodule